package gang.org.springframework.framework.factory;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author gang.chen
 * @since 2021/6/17 13:29
 */
public class GangDefaultSingletonBeanRegistry extends GangSimpleAliasRegistry implements GangSingletonBeanRegistry{

    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    public final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

    public final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

    public Object getSingleton(String beanName, GangObjectFactory<?> singletonFactory){

        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {

                //条件一

                //条件二

                //条件三

                boolean newSingleton = false;
                try{
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }catch (Exception e){
                    //TODO
                }finally {
                    //TODO
                }

                if (newSingleton) {
                    //TODO
                    addSingleton(beanName, singletonObject);
                }
            }

            return singletonObject;
        }


    }

    protected void addSingleton(String beanName, Object singletonObject){
        synchronized (this.singletonObjects){
            this.singletonObjects.put(beanName, singletonObject);
        }
    }

    @Override
    public void registerSingleton(String beanName, Object singletonObject) {
        synchronized(this.singletonObjects){
            Object oldObject = this.singletonObjects.get(beanName);
            if (oldObject != null) {
                System.out.println("Has Exception...");
            }
            addSingleton(beanName, singletonObject);
        }
    }

    @Override
    public boolean containsSingleton(String beanName) {
        //TODO 等编码
        return false;
    }

    /**
     * 对三个存储对象进行判定
     * 1）singletonObjects
     * 2）earlySingletonObjects
     * 3）singletonFactories
     * 注：spring bean 创建完成后，会将bean在3个Map， 1个set中进行存储
     * 业务意义
     * 创建spring bean将先确认该bean是否存在，在bean容器中
     * */
    @Override
    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }

    /**
     * 业务意义
     * 返回单例对象以bean名称为条件，验证已经实例化，同时允许一个引用，对于当前创建单例对象
     * */
    protected Object getSingleton(String beanName, boolean allowEarlyReference){
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentInCreation(beanName)) {
            //TODO
        }
        return singletonObject;
    }

    public boolean isSingletonCurrentInCreation(String beanName){
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }

    public void registerDependentBean(String beanName, String dependentBeanName){
        String canonicalName = canonicalName(beanName); //规范名称

        synchronized (this.dependentBeanMap) { //缓存
            Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
            if (!dependentBeans.add(dependentBeanName)) {
                return;
            }
        }

        synchronized (this.dependenciesForBeanMap) {
            Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
            dependenciesForBean.add(canonicalName);
        }

    }

}
